/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.mylhyl.zxing.scanner.scan.init;

import com.mylhyl.zxing.scanner.scan.util.CameraRatioUtil;
import com.mylhyl.zxing.scanner.scan.util.EmptyUtil;
import ohos.agp.graphics.Surface;
import ohos.agp.graphics.SurfaceOps;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.media.camera.CameraKit;
import ohos.media.camera.device.*;
import ohos.media.image.Image;
import ohos.media.image.ImageReceiver;
import ohos.media.image.common.ImageFormat;

import java.io.File;
import java.util.UUID;

/**
 * 相机初始化类
 */
public class CameraInit {

    /**
     * 相机运行线程名
     */
    private static final String EVENT_RUNNER_NAME = "LocalCamera";

    private static final String FRAME_RUNNER_NAME = "FrameCamera";

    /**
     * cameraKit对象
     */
    private static CameraKit cameraKit;

    /**
     * 预览surface
     */
    private Surface previewSurface;

    /**
     * 图像帧数据接收处理对象
     */
    private static ImageReceiver imageReceiver;

    /**
     * 相机属性
     */
    private CameraConfig.Builder cameraConfigBuilder;

    /**
     * 预览模板
     */
    private static FrameConfig.Builder frameConfigBuilder;

    private Context context;

    private static Camera myCamera;

    private SurfaceOps surfaceOps;

    public CameraInit(Context context, Surface surface, SurfaceOps surfaceOps) {
        this.context = context;
        this.previewSurface = surface;
        this.surfaceOps = surfaceOps;
    }

    /**
     * 创建相机
     *
     * @return
     */
    public boolean createCamera() {
        // 创建cameraKit对象
        boolean createKitState = this.createCameraKit(context);
        // 获取相机列表
        String[] cameraIds = this.getCameraIds();
        if (!createKitState || EmptyUtil.isEmpty(cameraIds)) {
            // 创建失败
            return false;
        }
        // 根据使用的前或后相机，获取cameraAbility对象
        CameraAbility cameraAbility = cameraKit.getCameraAbility(cameraIds[CameraInfoConfig.cameraType]);
        // 获取拍照支持的分辨率列表
        CameraInfoConfig.pictureSizes = cameraAbility.getSupportedSizes(ImageFormat.JPEG);
        // 获取最佳分辨率
        CameraInfoConfig.pictureOptimumSize = CameraRatioUtil.getOptimalPreviewSize(true, CameraInfoConfig.pictureSizes, CameraInfoConfig.cameraSize.width, CameraInfoConfig.cameraSize.height);
        // 设置预览surface属性
        this.setSurface(previewSurface);
        // 初始化图像接收器对象
        this.initImageReceiver();
        // 创建相机对象，会调用cameraStateCallback中的回调方法
        cameraKit.createCamera(cameraIds[CameraInfoConfig.cameraType], new CameraCallback(), new EventHandler(EventRunner.create(EVENT_RUNNER_NAME)));
        return true;
    }

    /**
     * 创建CameraKit对象
     *
     * @param context 上下文
     * @return
     */
    private boolean createCameraKit(Context context) {
        // 获取CameraKit实例
        cameraKit = CameraKit.getInstance(context);
        if (cameraKit == null) {
            return false;
        }
        return true;
    }

    /**
     * 获取相机id数组
     *
     * @return
     */
    private String[] getCameraIds() {
        String[] ids = null;
        try {
            ids = cameraKit.getCameraIds();
        } catch (IllegalStateException e) {
        }
        return ids;
    }

    /**
     * surface设置
     *
     * @param surface surface对象
     */
    private void setSurface(Surface surface) {
        // 设置原始图像数据格式、大小
        surface.showRawImage(
                new byte[Surface.PixelFormat.PIXEL_FORMAT_YCBCR_422_I.value() + CameraInfoConfig.pictureOptimumSize.width + CameraInfoConfig.pictureOptimumSize.height],
                Surface.PixelFormat.PIXEL_FORMAT_YCBCR_422_I,
                CameraInfoConfig.pictureOptimumSize.width,
                CameraInfoConfig.pictureOptimumSize.height);
        // 同步画布对象上的绘制调用以进行呈现。
        surface.syncCanvasDrawCalls();
    }

    private void initImageReceiver() {
        //  创建ImageReceiver对象，注意create函数中宽度要大于高度；5为最大支持的图像数，请根据实际设置。
        imageReceiver = ImageReceiver.create(Math.max(CameraInfoConfig.pictureOptimumSize.width, CameraInfoConfig.pictureOptimumSize.height),
                Math.min(CameraInfoConfig.pictureOptimumSize.width, CameraInfoConfig.pictureOptimumSize.height),
                ImageFormat.JPEG, 5);
        imageReceiver.setImageArrivalListener(imageArrivalListener);
    }

    public static void capture() {
        // 获取拍照配置模板
        frameConfigBuilder = myCamera.getFrameConfigBuilder(Camera.FrameConfigType.FRAME_CONFIG_PICTURE);
        // 配置拍照Surface
        frameConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
        // 配置拍照其他参数
        frameConfigBuilder.setImageRotation(90);
        try {
            // 启动单帧捕获(拍照)
            myCamera.triggerSingleCapture(frameConfigBuilder.build());
        } catch (IllegalArgumentException e) {
        } catch (IllegalStateException e) {
        }
    }

    /**
     * 单帧捕获生成图像回调Listener
     */
    private final ImageReceiver.IImageArrivalListener imageArrivalListener = new ImageReceiver.IImageArrivalListener() {
        @Override
        public void onImageArrival(ImageReceiver imageReceiver) {
            // 设置图片名
            StringBuffer fileName = new StringBuffer("picture_");
            fileName.append(UUID.randomUUID()).append(".jpg");
            File myFile = new File(fileName.toString());
            // 保存图片
            Image image = imageReceiver.readNextImage();
            ImageService imageService = new ImageService(image, myFile);
            EventHandler eventHandler = new EventHandler(EventRunner.create("CameraCb"));
            eventHandler.postTask(imageService);
        }
    };

    /**
     * 相机创建回调内部类
     */
    class CameraCallback extends CameraStateCallback {

        /**
         * 相机创建成功回调
         *
         * @param camera 相机对象
         */
        @Override
        public void onCreated(Camera camera) {
            myCamera = camera;
            // 相机配置
            cameraConfigBuilder = camera.getCameraConfigBuilder();
            // 设置预览surface
            cameraConfigBuilder.addSurface(previewSurface);
            // 设置拍照surface
            cameraConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
            // 配置帧结果的回调
            FrameCallBack frameStateCallBack = new FrameCallBack();
            EventHandler eventHandler = new EventHandler(EventRunner.create(FRAME_RUNNER_NAME));
            cameraConfigBuilder.setFrameStateCallback(frameStateCallBack, eventHandler);
            try {
                // 相机设备配置, 触发onConfigured回调
                camera.configure(cameraConfigBuilder.build());
            } catch (IllegalArgumentException e) {
            } catch (IllegalStateException e) {
            }
        }

        /**
         * 相机配置回调
         *
         * @param camera 相机对象
         */
        @Override
        public void onConfigured(Camera camera) {
            // 获取预览模板
            frameConfigBuilder = camera.getFrameConfigBuilder(Camera.FrameConfigType.FRAME_CONFIG_PREVIEW);
            // 配置预览surface
            frameConfigBuilder.addSurface(previewSurface);
            FrameConfig previewFrameConfig = frameConfigBuilder.build();
            // 启动帧捕获
            Integer triggerId;
            try {
                // 启动循环帧捕获,获取触发器id
                triggerId = camera.triggerLoopingCapture(previewFrameConfig);
            } catch (IllegalArgumentException e) {
            } catch (IllegalStateException e) {
            }
        }

        /**
         * 相机创建失败回调
         *
         * @param cameraId  相机id
         * @param errorCode 失败编码
         */
        @Override
        public void onCreateFailed(String cameraId, int errorCode) {

        }

        /**
         * 释放相机对象回调
         *
         * @param camera 相机对象
         */
        @Override
        public void onReleased(Camera camera) {
            // 释放相机设备
            camera.release();
        }
    }

}
